using System;
using System.Collections.Specialized;
using MetaBuilders.Irc.Messages;
using MetaBuilders.Irc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Globalization;

namespace MetaBuilders.NeboTests
{

	[TestClass]
	public class MessagesTest : MessageTester
	{

		[TestMethod]
		public void ParseDetermine()
		{
			String[] raws = new String[] {
				":foo!bar@zap.com PRIVMSG artificer :hello, how are you today?"
				,":foo!bar@zap.com NOTICE artificer :hello, how are you today?"
				,":foo!bar@zap.com PRIVMSG artificer :\x0001ACTION does some tests\x0001"
				,":foo!bar@zap.com 001 artificer :- Welcome To This IRC Server"
				,":foo!bar@zap.com NOTEXIST artificer :This Is Not In The RFC"
				,"PRIVMSG artificer :hello, how are you today?"
				,"NOTICE artificer :hello, how are you today?"
				,"PRIVMSG artificer :\x0001ACTION does some tests\x0001"
				,"001 artificer :- Welcome To This IRC Server"
				,"NOTEXIST artificer :This Is Not In The RFC"
				,":irc.easynews.com 001 NeboBot :Welcome to the EFNet IRC via EasyNews NeboBot"
				,":irc.easynews.com 375 NeboBot :- irc.easynews.com funky MOTD, read slow! -"
				,@":irc.easynews.com 353 artificer = #smack @artificer"
				,@":irc.easynews.com 366 artificer #smack :End of /NAMES list."
			};
			Type[] msgTypes = new Type[] {
				typeof( ChatMessage )
				,typeof( NoticeMessage )
				,typeof( ActionRequestMessage )
				,typeof( NumericMessage )
				,typeof( GenericMessage )
				,typeof( ChatMessage )
				,typeof( NoticeMessage )
				,typeof( ActionRequestMessage )
				,typeof( NumericMessage )
				,typeof( GenericMessage )
				,typeof( WelcomeMessage )
				,typeof( MotdStartReplyMessage )
				,typeof( NamesReplyMessage )
				,typeof( NamesEndReplyMessage )
			};

			for ( int i = 0; i < raws.Length; i++ )
			{
				String raw = raws[i];
				AssertRoundTripAndType( raw, msgTypes[i] );
			}

		}

		[TestMethod]
		public void UniqueReplyNumbers()
		{
			NameValueCollection foo = new NameValueCollection();
			foreach ( Type type in typeof( MetaBuilders.Irc.Messages.NumericMessage ).Assembly.GetTypes() )
			{
				if ( type.IsSubclassOf( typeof( NumericMessage ) ) && !type.IsAbstract )
				{
					NumericMessage msg = (NumericMessage)Activator.CreateInstance( type );
					//System.Reflection.PropertyInfo numericProperty = typeof( NumericMessage ).GetProperty( "InternalNumeric", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic );
					//String numeric = numericProperty.GetValue( msg, null ).ToString();
					String numeric = msg.InternalNumeric.ToString();

					if ( numeric != "-1" )
					{
						if ( foo[numeric] != null )
						{
							String otherType = foo[numeric];
							String thisType = type.FullName;
							Assert.Fail( "Shared Numeric, {0}, for '{1}' and '{2}'.", numeric, thisType, otherType );
						}
						foo[numeric] = type.FullName;
					}
				}
			}
		}

		[TestMethod]
		public void MessageSerialization()
		{
			NameValueCollection foo = new NameValueCollection();
			foreach ( Type type in typeof( MetaBuilders.Irc.Messages.IrcMessage ).Assembly.GetTypes() )
			{
				if ( type.IsAssignableFrom( typeof( IrcMessage ) ) || type.IsAssignableFrom( typeof( EventArgs ) ) )
				{
					if ( !type.IsSerializable )
					{
						Assert.Fail( "All Messages and Message EventArgs need to be serializable." );
					}
				}
			}
		}

		[TestMethod]
		public void CtcpUtilParsing()
		{
			String raw = ":foo!bar@zap.com PRIVMSG artificer :\x0001ACTION does some tests\x0001";

			String extendedData = CtcpUtil.GetExtendedData( raw );
			String internalCommand = CtcpUtil.GetInternalCommand( raw );
			String transportCommand = CtcpUtil.GetTransportCommand( raw );

			Assert.IsTrue( CtcpUtil.IsCtcpMessage( raw ), "Is Ctcp Message" );
			Assert.IsTrue( CtcpUtil.IsRequestMessage( raw ), "Is Ctcp Request" );
			Assert.AreEqual( "PRIVMSG", transportCommand, "Transport Command" );
			Assert.AreEqual( "ACTION", internalCommand, "Internal Command" );
			Assert.AreEqual( "does some tests", extendedData, "Extended Data" );


			raw = ":foo!bar@zap.com NOTICE artificer :\x0001VERSION NeboBot v0.2\x0001";

			extendedData = CtcpUtil.GetExtendedData( raw );
			internalCommand = CtcpUtil.GetInternalCommand( raw );
			transportCommand = CtcpUtil.GetTransportCommand( raw );

			Assert.IsTrue( CtcpUtil.IsCtcpMessage( raw ), "Is Ctcp Message" );
			Assert.IsTrue( CtcpUtil.IsReplyMessage( raw ), "Is Ctcp Reply" );
			Assert.AreEqual( "NOTICE", transportCommand, "Transport Command" );
			Assert.AreEqual( "VERSION", internalCommand, "Internal Command" );
			Assert.AreEqual( "NeboBot v0.2", extendedData, "Extended Data" );
		}

		[TestMethod]
		public void MessageUtilParsing()
		{
			String[] raws = new String[] {
				":foo!bar@zap.com PRIVMSG artificer :hello, how are you today?"
				,"NOTICE artificer,#smack :hello! : !assdlkjdf"
				,":foo!bar@zap.com SILENCE"
			};

			for ( Int32 i = 0; i < raws.Length; i++ )
			{
				String raw = raws[i];

				String prefix = MessageUtil.GetPrefix( raw );
				String command = MessageUtil.GetCommand( raw );
				StringCollection p = MessageUtil.GetParameters( raw );

				String expectedPrefix = "";
				String expectedCommand = "";
				Int32 expectedPCount = -1;

				switch ( i )
				{
					case 0:
						expectedPrefix = "foo!bar@zap.com";
						expectedCommand = "PRIVMSG";
						expectedPCount = 2;
						break;
					case 1:
						expectedPrefix = "";
						expectedCommand = "NOTICE";
						expectedPCount = 2;
						break;
					case 2:
						expectedPrefix = "foo!bar@zap.com";
						expectedCommand = "SILENCE";
						expectedPCount = 0;
						break;
				}

				Assert.AreEqual( expectedPrefix, prefix, "Prefix Test" );
				Assert.AreEqual( expectedCommand, command, "Command Test" );
				Assert.AreEqual( expectedPCount, p.Count, "Param Count Test" );


				switch ( i )
				{
					case 0:
						Assert.AreEqual( "artificer", p[0], "p target test" );
						Assert.AreEqual( "hello, how are you today?", p[1], "p text test" );
						break;
					case 1:
						Assert.AreEqual( "artificer,#smack", p[0], "p target test" );
						Assert.AreEqual( "hello! : !assdlkjdf", p[1], "p text test" );
						break;
				}
			}
		}

		#region Specific Messages

		[TestMethod]
		public void List()
		{
			String[] raws = new String[]
			{
				":irc.dkom.at LIST <10000,>499"
				,":irc.dkom.at LIST #foo"
			};

			ListMessage msg;

			msg = AssertRoundTripAndType( raws[0], typeof( ListMessage ) ) as ListMessage;
			Assert.AreEqual( 499, msg.MinUsers );
			Assert.AreEqual( 10000, msg.MaxUsers );

			msg = AssertRoundTripAndType( raws[1], typeof( ListMessage ) ) as ListMessage;
			Assert.AreEqual( "#foo", msg.Channels[0] );
		}

		[TestMethod]
		public void Wallchops()
		{
			String raw = "WALLCHOPS #foo :Test Message";
			WallchopsMessage msg = AssertRoundTripAndType( raw, typeof( WallchopsMessage ) ) as WallchopsMessage;

			Assert.AreEqual( "#foo", msg.Channel );
			Assert.AreEqual( "Test Message", msg.Text );
		}

		[TestMethod]
		public void Silence()
		{
			String[] raws = new String[] {
				"SILENCE +*!*@*.aol.com"
				,"SILENCE -foo"
				,"SILENCE"
			};
			String[] users = new String[] {
				"*!*@*.aol.com"
				,"foo"
				,""
			};
			ModeAction[] actions = new ModeAction[] {
				ModeAction.Add
				,ModeAction.Remove
				,ModeAction.Add
			};

			for ( Int32 i = 0; i < raws.Length; i++ )
			{
				String raw = raws[i];

				SilenceMessage msg = AssertRoundTripAndType( raw, typeof( SilenceMessage ) ) as SilenceMessage;
				Assert.AreEqual( users[i], msg.SilencedUser.ToString(), "SilencedUser" );
				Assert.AreEqual( msg.Action, actions[i], "Silence Action" );
			}

		}

		[TestMethod]
		public void SilenceReply()
		{
			String[] raws = new String[] {
				":broadway.ny.us.dal.net 271 olene olene *!*@*.aol.com"
			};
			String[] users = new String[] {
				"*!*@*.aol.com"
			};
			String[] owners = new String[] {
				"olene"
			};

			for ( Int32 i = 0; i < raws.Length; i++ )
			{
				String raw = raws[i];

				SilenceReplyMessage msg = AssertRoundTripAndType( raw, typeof( SilenceReplyMessage ) ) as SilenceReplyMessage;
				Assert.AreEqual( users[i], msg.SilencedUser.ToString(), "SilencedUser" );
				Assert.AreEqual( owners[i], msg.SilenceListOwner, "Silence List Owner" );
			}

		}

		[TestMethod]
		public void SilenceEndReply()
		{
			String raw = ":broadway.ny.us.dal.net 272 olene :End of /SILENCE list.";
			AssertRoundTripAndType( raw, typeof( SilenceEndReplyMessage ) );
		}

		[TestMethod]
		public void DccSend()
		{
			String raw = ":^Care|wrk!~carebear@212.4.54.137 PRIVMSG artificer :\x0001DCC SEND versions.txt 3557045897 1111 42740\x0001";
			DccSendRequestMessage msg = AssertRoundTripAndType( raw, typeof( DccSendRequestMessage ) ) as DccSendRequestMessage;

			Assert.AreEqual( "212.4.54.137", msg.Address.ToString(), "Address" );
			Assert.AreEqual( "versions.txt", msg.FileName, "FileName" );
			Assert.AreEqual( "1111", msg.Port.ToString(), "Port" );
			Assert.AreEqual( "42740", msg.Size.ToString(), "Size" );
			Assert.AreEqual( "^Care|wrk!~carebear@212.4.54.137", msg.Sender.ToString(), "Sender" );
			Assert.AreEqual( "artificer", msg.Target, "Target" );
		}

		[TestMethod]
		public void DccChat()
		{
			String raw = ":AndySmith!artificer@12-255-177-172.client.attbi.com PRIVMSG artificer :\x0001DCC CHAT chat 218083756 2777\x0001";
			DccChatRequestMessage msg = AssertRoundTripAndType( raw, typeof( DccChatRequestMessage ) ) as DccChatRequestMessage;

			Assert.AreEqual( "12.255.177.172", msg.Address.ToString(), "Address" );
			Assert.AreEqual( "2777", msg.Port.ToString(), "Port" );
			Assert.AreEqual( "AndySmith!artificer@12-255-177-172.client.attbi.com", msg.Sender.ToString(), "Sender" );
			Assert.AreEqual( "artificer", msg.Target, "Target" );
		}

		[TestMethod]
		public void NickInUse()
		{
			String raw = ":irc2.secsup.org 433 artificer COBOL :Nickname is already in use.";
			NickInUseMessage msg = AssertRoundTripAndType( raw, typeof( NickInUseMessage ) ) as NickInUseMessage;

			Assert.AreEqual( "COBOL", msg.Nick, "Nick" );
		}

		[TestMethod]
		public void ErroneusNick()
		{
			String raw = ":irc2.secsup.org 432 artificer #foo :Erroneus Nickname";
			ErroneousNickMessage msg = AssertRoundTripAndType( raw, typeof( ErroneousNickMessage ) ) as ErroneousNickMessage;

			Assert.AreEqual( "#foo", msg.Nick, "Nick" );
		}

		[TestMethod]
		public void PingPong()
		{
			String raw = "PING GDN-7T4JZ11";
			PingMessage msg = AssertRoundTripAndType( raw, typeof( PingMessage ) ) as PingMessage;
			Assert.AreEqual( "GDN-7T4JZ11", msg.Target, "Target" );

			PongMessage pong = new PongMessage();
			pong.Target = msg.Target;
			Assert.AreEqual( "PONG GDN-7T4JZ11", pong.ToString(), "Pong Reply" );
		}

		[TestMethod]
		public void ChannelModeMessage()
		{
			String raw = ":COBOL!~COBOL@ool-435015b7.dyn.optonline.net MODE #ms.net +o artificer";
			ChannelModeMessage msg = AssertRoundTripAndType( raw, typeof( ChannelModeMessage ) ) as ChannelModeMessage;

			Assert.AreEqual( "#ms.net", msg.Channel, "Channel" );
			Assert.AreEqual( "+o", msg.ModeChanges, "Mode Changes" );
			Assert.AreEqual( "artificer", msg.ModeArguments[0], "Mode Changes" );
		}

		[TestMethod]
		public void ServerInfoMessage()
		{
			String raw = ":irc2.secsup.org 004 artificer irc2.secsup.org 2.8/hybrid-6.3.1 oOiwszcrkfydnxb biklmnopstve";
			ServerInfoMessage msg = AssertRoundTripAndType( raw, typeof( ServerInfoMessage ) ) as ServerInfoMessage;
			Assert.AreEqual( "irc2.secsup.org", msg.ServerName );
			Assert.AreEqual( "2.8/hybrid-6.3.1", msg.Version );
			Assert.AreEqual( "oOiwszcrkfydnxb", msg.UserModes );
			Assert.AreEqual( "biklmnopstve", msg.ChannelModes );
		}

		[TestMethod]
		public void WelcomeMessage()
		{
			String raw = ":irc2.secsup.org 001 artificer :Welcome to the Internet Relay Network artificer";
			WelcomeMessage msg = AssertRoundTripAndType( raw, typeof( WelcomeMessage ) ) as WelcomeMessage;
			Assert.AreEqual( "Welcome to the Internet Relay Network artificer", msg.Text, "Welcome Text" );
		}

		[TestMethod]
		public void SupportMessage()
		{
			String[] raws = new String[] {
				":irc.easynews.com 005 artificer CHANLIMIT=#&:25 WALLCHOPS KNOCK EXCEPTS INVEX MODES=4 MAXCHANNELS=35 MAXBANS=25 MAXTARGETS=4 NICKLEN=9 TOPICLEN=120 KICKLEN=120 :are supported by this server"
				,":irc.foxlink.net 005 NeboBot STD=i-d STATUSMSG=@+ KNOCK EXCEPTS=e INVEX=I MODES=4 MAXCHANNELS=50 MAXLIST=beI:100 MAXTARGETS=7 NICKLEN=9 TOPICLEN=120 KICKLEN=120 :are supported by this server"
				,":irc.foxlink.net 005 NeboBot CHANTYPES=#& PREFIX=(ov)@+ CHANMODES=eIb,k,l,imnpst NETWORK=EFNet CASEMAPPING=rfc1459 CHARSET=ascii CALLERID ETRACE WALLCHOPS :are supported by this server"
			};

			for ( Int32 i = 0; i < raws.Length; i++ )
			{
				String raw = raws[i];
				SupportMessage msg = AssertRoundTripAndType( raw, typeof( SupportMessage ) ) as SupportMessage;
				ServerSupport support = new ServerSupport();
				support.LoadInfo( msg );

				switch ( i )
				{
					case 0:
						Assert.AreEqual( 12, msg.SupportedItems.Count, "SupportItems Count" );
						Assert.IsNotNull( msg.SupportedItems["CHANLIMIT"], "CHANLIMIT" );
						Assert.IsNotNull( msg.SupportedItems["WALLCHOPS"], "WALLCHOPS" );
						Assert.IsNotNull( msg.SupportedItems["KNOCK"], "KNOCK" );
						Assert.IsNotNull( msg.SupportedItems["EXCEPTS"], "EXCEPTS" );
						Assert.IsNotNull( msg.SupportedItems["INVEX"], "INVEX" );
						Assert.IsNotNull( msg.SupportedItems["MODES"], "MODES" );
						Assert.IsNotNull( msg.SupportedItems["MAXCHANNELS"], "MAXCHANNELS" );
						Assert.IsNotNull( msg.SupportedItems["MAXBANS"], "MAXBANS" );
						Assert.IsNotNull( msg.SupportedItems["MAXTARGETS"], "MAXTARGETS" );
						Assert.IsNotNull( msg.SupportedItems["NICKLEN"], "NICKLEN" );
						Assert.IsNotNull( msg.SupportedItems["TOPICLEN"], "TOPICLEN" );
						Assert.IsNotNull( msg.SupportedItems["KICKLEN"], "KICKLEN" );
						Assert.AreEqual( "#&:25", msg.SupportedItems["CHANLIMIT"], "CHANLIMIT" );
						Assert.AreEqual( "4", msg.SupportedItems["MODES"], "MODES" );
						Assert.AreEqual( "35", msg.SupportedItems["MAXCHANNELS"], "MAXCHANNELS" );
						Assert.AreEqual( "25", msg.SupportedItems["MAXBANS"], "MAXBANS" );
						Assert.AreEqual( "4", msg.SupportedItems["MAXTARGETS"], "MAXTARGETS" );
						Assert.AreEqual( "9", msg.SupportedItems["NICKLEN"], "NICKLEN" );
						Assert.AreEqual( "120", msg.SupportedItems["TOPICLEN"], "TOPICLEN" );
						Assert.AreEqual( "120", msg.SupportedItems["KICKLEN"], "KICKLEN" );

						Assert.AreEqual( 2, support.ChannelLimits.Count, "ChannelLimits" );
						Assert.AreEqual( 25, support.ChannelLimits["#"], "ChannelLimits" );
						Assert.AreEqual( 25, support.ChannelLimits["&"], "ChannelLimits" );
						Assert.IsTrue( support.MessagesToOperators, "MessagesToOperators" );
						Assert.IsTrue( support.Knock, "Knock" );
						Assert.IsTrue( support.BanExceptions, "BanExceptions" );
						Assert.IsTrue( support.InvitationExceptions, "InvitationExceptions" );
						Assert.AreEqual( 4, support.MaxModes, "MaxModes" );
						Assert.AreEqual( 35, support.MaxChannels, "MaxChannels" );
						Assert.AreEqual( 25, support.MaxBans, "MaxBans" );
						Assert.AreEqual( 4, support.MaxMessageTargets[""], "MaxMessageTargets" );
						Assert.AreEqual( 9, support.MaxNickLength, "MaxNickLength" );
						Assert.AreEqual( 120, support.MaxTopicLength, "MaxTopicLength" );
						Assert.AreEqual( 120, support.MaxKickCommentLength, "MaxKickCommentLength" );

						break;
					case 1:
						Assert.AreEqual( 12, msg.SupportedItems.Count, "SupportedItems Count" );
						Assert.IsNotNull( msg.SupportedItems["STD"], "STD" );
						Assert.IsNotNull( msg.SupportedItems["STATUSMSG"], "STATUSMSG" );
						Assert.IsNotNull( msg.SupportedItems["KNOCK"], "KNOCK" );
						Assert.IsNotNull( msg.SupportedItems["EXCEPTS"], "EXCEPTS" );
						Assert.IsNotNull( msg.SupportedItems["INVEX"], "INVEX" );
						Assert.IsNotNull( msg.SupportedItems["MODES"], "MODES" );
						Assert.IsNotNull( msg.SupportedItems["MAXCHANNELS"], "MAXCHANNELS" );
						Assert.IsNotNull( msg.SupportedItems["MAXLIST"], "MAXLIST" );
						Assert.IsNotNull( msg.SupportedItems["MAXTARGETS"], "MAXTARGETS" );
						Assert.IsNotNull( msg.SupportedItems["NICKLEN"], "NICKLEN" );
						Assert.IsNotNull( msg.SupportedItems["TOPICLEN"], "TOPICLEN" );
						Assert.IsNotNull( msg.SupportedItems["KICKLEN"], "KICKLEN" );

						Assert.AreEqual( "i-d", msg.SupportedItems["STD"], "STD" );
						Assert.AreEqual( "@+", msg.SupportedItems["STATUSMSG"], "STATUSMSG" );
						Assert.AreEqual( "e", msg.SupportedItems["EXCEPTS"], "EXCEPTS" );
						Assert.AreEqual( "I", msg.SupportedItems["INVEX"], "INVEX" );
						Assert.AreEqual( "4", msg.SupportedItems["MODES"], "MODES" );
						Assert.AreEqual( "50", msg.SupportedItems["MAXCHANNELS"], "MAXCHANNELS" );
						Assert.AreEqual( "beI:100", msg.SupportedItems["MAXLIST"], "MAXLIST" );
						Assert.AreEqual( "7", msg.SupportedItems["MAXTARGETS"], "MAXTARGETS" );
						Assert.AreEqual( "9", msg.SupportedItems["NICKLEN"], "NICKLEN" );
						Assert.AreEqual( "120", msg.SupportedItems["TOPICLEN"], "TOPICLEN" );
						Assert.AreEqual( "120", msg.SupportedItems["KICKLEN"], "KICKLEN" );

						Assert.AreEqual( "i-d", support.Standard, "Standard" );
						Assert.AreEqual( "@+", support.StatusMessages, "StatusMessages" );
						Assert.IsTrue( support.Knock, "Knock" );
						Assert.IsTrue( support.BanExceptions, "BanExceptions" );
						Assert.IsTrue( support.InvitationExceptions, "InvitationExceptions" );
						Assert.AreEqual( 4, support.MaxModes, "MaxModes" );
						Assert.AreEqual( 50, support.MaxChannels, "MaxChannels" );
						Assert.AreEqual( 100, support.MaxBans, "MaxBans" );
						Assert.AreEqual( 100, support.MaxBanExceptions, "MaxBanExceptions" );
						Assert.AreEqual( 100, support.MaxInvitationExceptions, "MaxInvitationExceptions" );
						Assert.AreEqual( 7, support.MaxMessageTargets[""], "MaxMessageTargets" );
						Assert.AreEqual( 9, support.MaxNickLength, "MaxNickLength" );
						Assert.AreEqual( 120, support.MaxTopicLength, "MaxTopicLength" );
						Assert.AreEqual( 120, support.MaxKickCommentLength, "MaxKickCommentLength" );

						break;
					case 2:
						Assert.AreEqual( 9, msg.SupportedItems.Count, "SupportedItems Count" );
						Assert.IsNotNull( msg.SupportedItems["CHANTYPES"], "CHANTYPES" );
						Assert.IsNotNull( msg.SupportedItems["PREFIX"], "PREFIX" );
						Assert.IsNotNull( msg.SupportedItems["CHANMODES"], "CHANMODES" );
						Assert.IsNotNull( msg.SupportedItems["NETWORK"], "NETWORK" );
						Assert.IsNotNull( msg.SupportedItems["CASEMAPPING"], "CASEMAPPING" );
						Assert.IsNotNull( msg.SupportedItems["CHARSET"], "CHARSET" );
						Assert.IsNotNull( msg.SupportedItems["CALLERID"], "CALLERID" );
						Assert.IsNotNull( msg.SupportedItems["ETRACE"], "ETRACE" );
						Assert.IsNotNull( msg.SupportedItems["WALLCHOPS"], "WALLCHOPS" );

						Assert.AreEqual( "#&", msg.SupportedItems["CHANTYPES"], "CHANTYPES" );
						Assert.AreEqual( "(ov)@+", msg.SupportedItems["PREFIX"], "PREFIX" );
						Assert.AreEqual( "eIb,k,l,imnpst", msg.SupportedItems["CHANMODES"], "CHANMODES" );
						Assert.AreEqual( "EFNet", msg.SupportedItems["NETWORK"], "NETWORK" );
						Assert.AreEqual( "rfc1459", msg.SupportedItems["CASEMAPPING"], "CASEMAPPING" );
						Assert.AreEqual( "ascii", msg.SupportedItems["CHARSET"], "CHARSET" );

						Assert.IsTrue( support.CallerId, "CallerId" );
						Assert.IsTrue( support.ETrace, "ETrace" );
						Assert.IsTrue( support.MessagesToOperators, "MessagesToOperators" );
						Assert.AreEqual( 2, support.ChannelTypes.Count, "ChannelTypes" );
						Assert.AreEqual( "(ov)@+", support.ChannelStatuses, "ChannelStatuses" );
						Assert.AreEqual( 4, support.ModesWithParameters.Count, "ModesWithParameters" );
						Assert.AreEqual( 6, support.ModesWithoutParameters.Count, "ModesWithoutParameters" );
						Assert.AreEqual( 1, support.ModesWithParametersWhenSet.Count, "ModesWithParametersWhenSet" );
						Assert.AreEqual( "EFNet", support.NetworkName, "NetworkName" );
						Assert.AreEqual( "rfc1459", support.CaseMapping, "CaseMapping" );
						Assert.AreEqual( "ascii", support.CharacterSet, "CharacterSet" );

						break;
				}
			}
		}

		[TestMethod]
		public void PartMessage()
		{
			String[] raws = new String[] {
				":atchr!~antichron@pcp407739pcs.waldrf01.md.comcast.net PART #ms.net"
				,":atchr!~antichron@pcp407739pcs.waldrf01.md.comcast.net PART #ms.net,#mscorlib :You solved all my problems."
			};
			String[][] channels = new String[][] {
				new String[] { "#ms.net" }
				,new String[] { "#ms.net", "#mscorlib" }
			};
			String[] reasons = new String[] {
				""
				,"You solved all my problems."
			};

			for ( int i = 0; i < raws.Length; i++ )
			{
				String raw = raws[i];
				PartMessage msg = AssertRoundTripAndType( raw, typeof( PartMessage ) ) as PartMessage;
				Assert.AreEqual( reasons[i], msg.Reason, "Reason" );
				for ( int j = 0; j < msg.Channels.Count; j++ )
				{
					Assert.AreEqual( channels[i][j], msg.Channels[j], "Channel" );
				}
			}

		}

		[TestMethod]
		public void TimeRequestMessage()
		{
			String raw = ":liKwid|ii!iridium@kernel.hacking.no PRIVMSG artificer \x0001TIME\x0001";
			TimeRequestMessage msg = AssertRoundTripAndType( raw, typeof( TimeRequestMessage ) ) as TimeRequestMessage;
		}

		[TestMethod]
		public void JoinMessage()
		{
			String[] initialRaw = new String[] {
				":artificer!artificer@12-255-177-172.client.attbi.com JOIN #ms.net",
				":artificer!artificer@12-255-177-172.client.attbi.com JOIN #ms.net,#mscorlib",
				":artificer!artificer@12-255-177-172.client.attbi.com JOIN #ms.net myKey",
				":artificer!artificer@12-255-177-172.client.attbi.com JOIN #ms.net,#mscorlib myKey,myOtherKey",
				":artificer JOIN #foo"
			};
			String[][] channels = new String[][] {
				new String[] { "#ms.net" }
				,new String[] { "#ms.net", "#mscorlib" }
				,new String[] { "#ms.net" }
				,new String[] { "#ms.net", "#mscorlib" }
				,new String[] { "#foo" }
			};
			String[][] keys = new String[][] {
				new String[]{}
				,new String[]{}
				,new String[]{ "myKey" }
				,new String[]{ "myKey", "myOtherKey" }
				,new String[]{}
			};

			for ( Int32 i = 0; i < initialRaw.Length; i++ )
			{
				JoinMessage msg = AssertRoundTripAndType( initialRaw[i], typeof( JoinMessage ) ) as JoinMessage;
				for ( Int32 j = 0; j < msg.Channels.Count; j++ )
				{
					Assert.AreEqual( channels[i][j], msg.Channels[j], "Channels" );
				}
				for ( Int32 k = 0; k < msg.Keys.Count; k++ )
				{
					Assert.AreEqual( keys[i][k], msg.Keys[k], "Keys" );
				}
			}
		}

		[TestMethod]
		public void YourHostIsMessageTest()
		{
			String raw = ":irc.easynews.com 002 NeboBot :Your host is irc.easynews.com[irc.easynews.com/6667], running version ircd-ratbox-1.1rc1";
			YourHostMessage msg = AssertRoundTripAndType( raw, typeof( YourHostMessage ) ) as YourHostMessage;
			Assert.AreEqual( "irc.easynews.com[irc.easynews.com/6667]", msg.ServerName, "ServerName" );
			Assert.AreEqual( "ircd-ratbox-1.1rc1", msg.Version, "Version" );
		}

		[TestMethod]
		public void ServerCreatedMessageTest()
		{
			String raw = ":irc.easynews.com 003 NeboBot :This server was created Thu Dec 26 2002 at 15:52:56 MST";
			ServerCreatedMessage msg = AssertRoundTripAndType( raw, typeof( ServerCreatedMessage ) ) as ServerCreatedMessage;
			Assert.AreEqual( "Thu Dec 26 2002 at 15:52:56 MST", msg.CreatedDate, "CreatedDate" );
		}

		[TestMethod]
		public void LusersReplyMessageTest()
		{
			String raw = ":irc.easynews.com 251 NeboBot :There are 7012 users and 112533 invisible on 50 servers";
			LusersReplyMessage msg = AssertRoundTripAndType( raw, typeof( LusersReplyMessage ) ) as LusersReplyMessage;
			Assert.AreEqual( 7012, msg.UserCount, "UserCount" );
			Assert.AreEqual( 112533, msg.InvisibleCount, "InvisibleCount" );
			Assert.AreEqual( 50, msg.ServerCount, "ServerCount" );
		}

		[TestMethod]
		public void LusersOpReplyMessageTest()
		{
			String initialRaw = ":irc.easynews.com 252 NeboBot 350 :POWER RANGER IRC Operators online";
			LusersOpReplyMessage msg = AssertRoundTripAndType( initialRaw, typeof( LusersOpReplyMessage ) ) as LusersOpReplyMessage;
			Assert.AreEqual( 350, msg.OpCount, "OpCount" );
			Assert.AreEqual( "POWER RANGER IRC Operators online", msg.Info, "Info" );
		}

		[TestMethod]
		public void LusersChannelsReplyMessageTest()
		{
			String initialRaw = ":irc.easynews.com 254 NeboBot 42533 :channels formed";
			LusersChannelsReplyMessage msg = AssertRoundTripAndType( initialRaw, typeof( LusersChannelsReplyMessage ) ) as LusersChannelsReplyMessage;
			Assert.AreEqual( 42533, msg.ChannelCount, "ChannelCount" );
		}

		[TestMethod]
		public void LusersMeReplyMessageTest()
		{
			String initialRaw = ":irc.easynews.com 255 NeboBot :I have 9638 clients and 1 servers";
			LusersMeReplyMessage msg = AssertRoundTripAndType( initialRaw, typeof( LusersMeReplyMessage ) ) as LusersMeReplyMessage;
			Assert.AreEqual( 9638, msg.ClientCount, "ClientCount" );
			Assert.AreEqual( 1, msg.ServerCount, "ServerCount" );
		}

		[TestMethod]
		public void LocalUsersReplyMessageTest()
		{
			String[] raws = new String[] {
				 ":irc.easynews.com 265 NeboBot :Current local users: 9638 Max: 13035"
				,":irc.ptptech.com 265 artificer 606 610 :Current local users 606, max 610"
			};

			LocalUsersReplyMessage msg;

			msg = AssertRoundTripAndType( raws[0], typeof( LocalUsersReplyMessage ) ) as LocalUsersReplyMessage;
			Assert.AreEqual( 9638, msg.UserCount, "UserCount" );
			Assert.AreEqual( 13035, msg.UserLimit, "UserLimit" );

			// the second one will not be a valid round trip.
			msg = MessageParserService.Service.Parse( raws[1] ) as LocalUsersReplyMessage;
			Assert.AreEqual( 606, msg.UserCount, "UserCount" );
			Assert.AreEqual( 610, msg.UserLimit, "UserLimit" );
		}

		[TestMethod]
		public void GlobalUsersReplyMessageTest()
		{
			String[] raws = new String[] {
				 ":irc.easynews.com 266 NeboBot :Current global users: 119545 Max: 131548"
				,":irc.ptptech.com 266 artificer 84236 87756 :Current global users 84236, max 87756"
			};

			GlobalUsersReplyMessage msg;

			msg = AssertRoundTripAndType( raws[0], typeof( GlobalUsersReplyMessage ) ) as GlobalUsersReplyMessage;
			Assert.AreEqual( 119545, msg.UserCount, "UserCount" );
			Assert.AreEqual( 131548, msg.UserLimit, "UserLimit" );

			// the second one will not be a valid round trip.
			msg = MessageParserService.Service.Parse( raws[1] ) as GlobalUsersReplyMessage;
			Assert.AreEqual( 84236, msg.UserCount, "UserCount" );
			Assert.AreEqual( 87756, msg.UserLimit, "UserLimit" );

		}

		[TestMethod]
		public void TopicSetReplyMessageTest()
		{
			String initialRaw = ":irc.easynews.com 333 NeboBot #ms.net ^Care|wrk!~carebear@212.4.54.137 104403576";
			TopicSetReplyMessage msg = AssertRoundTripAndType( initialRaw, typeof( TopicSetReplyMessage ) ) as TopicSetReplyMessage;
			Assert.AreEqual( "#ms.net", msg.Channel, "Channel" );
			Assert.AreEqual( MessageUtil.ConvertFromUnixTime( 104403576 ), msg.TimeSet, "TimeSet" );
			Assert.AreEqual( "^Care|wrk!~carebear@212.4.54.137", msg.User.ToString(), "User" );
		}

		[TestMethod]
		public void StatsReplyMessageTest()
		{
			String initialRaw = ":irc.easynews.com 250 NeboBot :Highest connection count: 13036 (13035 clients) (1042354 connections received)";
			StatsReplyMessage msg = AssertRoundTripAndType( initialRaw, typeof( StatsReplyMessage ) ) as StatsReplyMessage;
			Assert.AreEqual( "Highest connection count: 13036 (13035 clients) (1042354 connections received)", msg.Stats, "Stats" );
		}

		[TestMethod]
		public void ChatMessageRoundTrip()
		{
			String initialRaw = ":foo!bar@zap.com PRIVMSG artificer :hello, how are you today?";
			ChatMessage msg = AssertRoundTripAndType( initialRaw, typeof( ChatMessage ) ) as ChatMessage;
			Assert.AreEqual( "foo!bar@zap.com", msg.Sender.ToString(), "Sender" );
			Assert.AreEqual( "artificer", msg.Targets[0], "Target" );
			Assert.AreEqual( "hello, how are you today?", msg.Text, "Text" );
		}

		[TestMethod]
		public void NoticeMessageRoundTrip()
		{
			String initialRaw = ":foo!bar@zap.com NOTICE artificer,#smack :hello, how are you today?";
			NoticeMessage msg = AssertRoundTripAndType( initialRaw, typeof( NoticeMessage ) ) as NoticeMessage;
			Assert.AreEqual( "foo!bar@zap.com", msg.Sender.ToString(), "Sender" );
			Assert.AreEqual( "artificer", msg.Targets[0], "Target1" );
			Assert.AreEqual( "#smack", msg.Targets[1], "Target2" );
			Assert.AreEqual( "hello, how are you today?", msg.Text, "Text" );
		}

		[TestMethod]
		public void UniqueIdMessageTest()
		{
			List<String> raws = new List<String> {
				":irc.inter.net.il 042 NeboBot NeboBot 5ILABFZUY :your unique ID"
				,":irc.inter.net.il 042 NeboBot NeboBot 5ILABFZW7 :your unique ID"
				,":us.ircnet.org 042 NeboBot NeboBot 0PNUACUZI :your unique ID"
			};

			for ( int i = 0; i < raws.Count; i++ )
			{
				String raw = raws[i];
				UniqueIdMessage msg = AssertRoundTripAndType( raw, typeof( UniqueIdMessage ) ) as UniqueIdMessage;
				switch ( i )
				{
					case 0:
						Assert.AreEqual( "5ILABFZUY", msg.UniqueId, false, CultureInfo.InvariantCulture, "UniqueId" );
						break;
					case 1:
						Assert.AreEqual( "5ILABFZW7", msg.UniqueId, false, CultureInfo.InvariantCulture, "UniqueId" );
						break;
					case 2:
						Assert.AreEqual( "0PNUACUZI", msg.UniqueId, false, CultureInfo.InvariantCulture, "UniqueId" );
						break;
				}
			}
		}

		#endregion

	}

}

